package com.hy.search.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.hy.common.enums.ExceptionEnums;
import com.hy.common.exception.XkException;
import com.hy.common.utils.JsonUtils;
import com.hy.common.utils.NumberUtils;
import com.hy.common.vo.PageResult;
import com.hy.item.pojo.*;
import com.hy.search.client.BrandClient;
import com.hy.search.client.CategoryClient;
import com.hy.search.client.GoodsClient;
import com.hy.search.client.SpecificationClient;
import com.hy.search.pojo.Goods;
import com.hy.search.pojo.SearchRequest;
import com.hy.search.repository.GoodsRepository;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchService {

    @Autowired
    private CategoryClient categoryClient;
    @Autowired
    private BrandClient brandClient;
    @Autowired
    private GoodsClient goodsClient;
    @Autowired
    private SpecificationClient specClient;

    public Goods buildGoods(Spu spu){
         //=====================================================
        //查询分类
        List<Category> categories = categoryClient.queryCategoryByIds(
                Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));

        if (CollectionUtils.isEmpty(categories)){
            throw new XkException(ExceptionEnums.CATEGORY_NOT_FOUND);
        }
        List<String> names = categories.stream().map(Category::getName)
                .collect(Collectors.toList());
        //查询品牌
        Brand brand = brandClient.queryBrandById(spu.getBrandId());
        if (brand==null){
            throw new XkException(ExceptionEnums.BRAND_NOT_FOUND);
        }
        //搜索字段
        String all=spu.getTitle()+ StringUtils.join(names," ");
        //==============================================
        //查询sku的集合和sku中价格的集合
        List<Sku> skus = goodsClient.querySkuById(spu.getId());
        Set<Long> priceList = skus.stream().map(Sku::getPrice).collect(Collectors.toSet());
        //====================================================
       //查询规格参数
        List<SpecParam> params = specClient.queryParamList(null, spu.getCid3(), true);
        //查询商品详情
        SpuDetail spuDetail = goodsClient.queryDetailById(spu.getId());
        //获通用规格参数和特有规格参数
        String genericSpec = spuDetail.getGenericSpec();
        String specialSpec = spuDetail.getSpecialSpec();
        //因为通用和特有的是json字符串，字符传中是k-v结构，
        //通过规格参数id找json字符串中的值不好找，所以将通用和特有转换成map
        Map<Long, String> ptMap = JsonUtils.toMap(genericSpec, Long.class, String.class);//通用规格
        //特有规格属性
        Map<Long, List<Object>> tsMap
                = JsonUtils.nativeRead(specialSpec, new TypeReference<Map<Long, List<Object>>>() {
        });

        //规格参数是一个map,key在规格参数表，value在商品详情
        Map<String, Object> map = new HashMap<String,Object>();
        for (SpecParam param:params){
            Object value="";
            String key = param.getName();//规格参数的名字作为key
            //判断是否是通用规格
            if (param.getGeneric()){
                 value = ptMap.get(param.getId());
                 //判断是否是数值类型 如传过来的是5.5英寸是数值类型
                if (param.getNumeric()){
                        //处理成段 如：5.0-6英寸这样的断段。然后将返回过来的段将原先的数值类型的value覆盖
                        value=chooseSegment(value.toString(),param);
                }
            }else {
                value=tsMap.get(param.getId());
            }
            //将key,value放到map中
            map.put(key,value);
        }
        //==============================================================
        Goods goods = new Goods();
        goods.setBrandId(spu.getBrandId());
        goods.setCid1(spu.getCid1());
        goods.setCid2(spu.getCid2());
        goods.setCid3(spu.getCid3());
        goods.setCreateTime(spu.getCreateTime());
        goods.setId(spu.getId());
        goods.setAll(all);// 搜索字段，包含标题，字段，分类，品牌，规格等
        goods.setPrice(priceList);//搜索sku的价格的集合
        goods.setSkus(JsonUtils.toString(skus));//所有sku的集合的jsong格式
        goods.setSpecs(map);//所有可搜索的规格的参数,key为规格参数名字，value为规格参数的值
        goods.setSubTitle(spu.getSubTitle());
        return goods;
    }


    private String chooseSegment(String value, SpecParam p) {
        double val = NumberUtils.toDouble(value);
        String result = "其它";
        // 保存数值段
        for (String segment : p.getSegments().split(",")) {
            String[] segs = segment.split("-");
            // 获取数值范围
            double begin = NumberUtils.toDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if(segs.length == 2){
                end = NumberUtils.toDouble(segs[1]);
            }
            // 判断是否在范围内
            if(val >= begin && val < end){
                if(segs.length == 1){
                    result = segs[0] + p.getUnit() + "以上";
                }else if(begin == 0){
                    result = segs[1] + p.getUnit() + "以下";
                }else{
                    result = segment + p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    /**
     * 带分页的搜索
     * @param searchRequest
     * @return
     */
    @Autowired
    private GoodsRepository repository;

    public PageResult<Goods> search(SearchRequest searchRequest) {

        int page = searchRequest.getPage()-1;//elasticSearch当前页是从0开始的
        int size = searchRequest.getSize();
        //创建查询的构造器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //0 结果过滤，结果中只要页面中展示的那三个字段即可
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"id","subTitle","skus"},null));
        //1 分页
        queryBuilder.withPageable(PageRequest.of(page,size));
        //2过滤,第一个参数是查询的字段，第二个是查询的条件
        queryBuilder.withQuery(QueryBuilders.matchQuery("all",searchRequest.getKey()));
       //3 查询
        Page<Goods> result = repository.search(queryBuilder.build());
        //4 解析结果
        long total = result.getTotalElements();//总条数
        int totalPages = result.getTotalPages();//总页数
        List<Goods> goodsList = result.getContent();//总记录数

        PageResult<Goods> goodsPageResult = new PageResult<>(total, totalPages, goodsList);
        return goodsPageResult;


    }
    /**
     * 对索引库中的的数据进行新增或者修改
     */
    public void createOrUpdateIndex(Long spuId) {
        //查询spu
        Spu spu = goodsClient.querySpuById(spuId);
        //构建goods对象
        Goods goods = buildGoods(spu);
        //存入索引库
        repository.save(goods);
    }
}
